﻿using project.B12.IRepository;
using project.B12.IService;
using project.B12.Model.Models;
using SqlSugar;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Windows.Media.Imaging;

namespace project.B12.Service
{
    /// <summary>
    /// 图片处理
    /// </summary>
    public class ServiceImageProcessing : IServiceImageProcessing
    {
        public IConfigurationFileManagement configurationFileManagement;
        public IMICPlateMes mICPlateMes;
        public ServiceImageProcessing(IConfigurationFileManagement _configurationFileManagement, IMICPlateMes _mICPlateMes)
        {
            configurationFileManagement = _configurationFileManagement;
            this.mICPlateMes = _mICPlateMes; 
        }

        /// <summary>
        /// 裁剪并保存照片
        /// </summary>
        /// <param name="savePath"></param>
        /// <param name="bmpOrig">4x4的照片</param>
        /// <param name="index"></param>
        /// <param name="plateStyle"></param>
        /// <exception cref="Exception"></exception>
        [SupportedOSPlatform("windows")]
        public void CutAndSave(string savePath,Bitmap bmpOrig,int index, string plateStyle)
        {

            if (string.IsNullOrEmpty(savePath))
            {
                 return;//TODO
            }
            else
            {
                if (!Directory.Exists(savePath))
                {
                    DirectoryInfo dirInfo = new DirectoryInfo(savePath);
                    dirInfo.Create();
                }
                else
                {
                   //TODO
                }
            }
            var mf = mICPlateMes.microplateAntibioticConcentrationMes.Find(p => p.name == plateStyle);
            if (mf == null)
            {
                throw new Exception("配置文件错误");
            }
            var map = configurationFileManagement.GetMapCfgByName(mf.Map);
            try
            {
                var bmpCutOrg = bmpOrig;
                int dY = map.dx;
                int dX = map.dy;
                int weight = map.width;
                int height = map.height;

                for (int i = 0; i < 16; i++)
                {
                    int holeX = (int)map.GetType().GetProperty($"holeX{i + 1}").GetValue(map);
                    int holeY = (int)map.GetType().GetProperty($"holeY{i + 1}").GetValue(map);
                    Rectangle cutRec = new Rectangle()
                    {
                        X = holeX - weight / 2,
                        Y = holeY - height / 2,
                        Width = weight,
                        Height = height
                    };
                    var holePic = cutPicture(bmpCutOrg, cutRec);
                    if (holePic != null)
                    {
                        int nameIndex = i % 4 + (i / 4) * 12 + 1 + index * 4 + index / 3 * 36;
                        holePic.Save(Path.Combine(savePath, $"temp{nameIndex}.jpeg"),ImageFormat.Jpeg);
                        saveUsefulPic(holePic, map.Fill, map.Square,Path.Combine(savePath, $"{nameIndex}.jpg"));
                    }
                }  
            }
            catch (Exception ex)
            {
                throw ex;
            }
        } 

       /// <summary>
       /// 
       /// </summary>
       /// <param name="orgBMP"></param>
       /// <param name="cutRec"></param>
       /// <returns></returns>
        private static Bitmap cutPicture(Bitmap orgBMP, Rectangle cutRec)
        {
            //判断超出的位置否
            if ((orgBMP.Width < cutRec.X + cutRec.Width) || orgBMP.Height < cutRec.Y + cutRec.Height)
            {
                //TODO 裁剪尺寸超出原有尺寸
                // MessageBox.Show("裁剪尺寸超出原有尺寸！");
                return null;
            }
            //进行裁剪
            return orgBMP.Clone(cutRec, orgBMP.PixelFormat);
        }

        private void saveUsefulPic(Bitmap img,int R,int Square, string path)
        {
            try
            {
                if (img.PixelFormat == System.Drawing.Imaging.PixelFormat.Format8bppIndexed)
                {
                    Rectangle cutRec = new Rectangle()
                    {
                        X = img.Width / 2 - Square / 2,
                        Y = img.Height / 2 - Square / 2,
                        Width = Square,
                        Height = Square
                    };
                    var afterPic = cutPicture(img, cutRec);
                    byte[] byBuffer = new byte[afterPic.Width * afterPic.Height];
                    Bitmap  bitmap = new Bitmap(afterPic.Width, afterPic.Height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
                    BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
                    if (bitmap.PixelFormat == System.Drawing.Imaging.PixelFormat.Format8bppIndexed)
                    {
                        ColorPalette colorPalette = bitmap.Palette;
                        for (int i = 0; i < 256; i++)
                        {
                            colorPalette.Entries[i] = System.Drawing.Color.FromArgb(i, i, i);
                        }
                        bitmap.Palette = colorPalette;
                    }
                  
                    for (int i = 0; i < afterPic.Height; i++)
                    {
                        for (int j = 0; j < afterPic.Width; j++)
                        {
                            if (inR(j, i, afterPic.Width / 2, afterPic.Height / 2, R/2))
                            {
                                System.Drawing.Color rgb = afterPic.GetPixel(j, i);
                                byBuffer[i* afterPic.Width+j] = (byte)((rgb.R + rgb.G + rgb.B) / 3);
  
                            }
                            else
                            {
                                byBuffer[i * afterPic.Width + j] = 255;
                            }
                        }
                    }
                    IntPtr ptrBmp = bmpData.Scan0;
                    int nImageStride = bitmap.Width;
                    //图像宽能够被4整除直接copy
                    if (nImageStride == bmpData.Stride)
                    {
                        Marshal.Copy(byBuffer, 0, ptrBmp, bmpData.Stride * bitmap.Height);
                    }
                    else//图像宽不能够被4整除按照行copy
                    {
                        for (int i = 0; i < bitmap.Height; ++i)
                        {
                            Marshal.Copy(byBuffer, i * nImageStride, new IntPtr(ptrBmp.ToInt64() + i * bmpData.Stride), bitmap.Width);
                        }
                    }
                    //BitmapData解锁
                    bitmap.UnlockBits(bmpData);
                    bitmap.Save(path, ImageFormat.Jpeg);
                }
                else
                {
                    //Bitmap bm = new Bitmap(Square, Square, img.PixelFormat);
                    //Graphics g = Graphics.FromImage(bm);
                    //g.FillRectangle(System.Drawing.Brushes.White, new Rectangle(0, 0, Square, Square));
                    ////创建截图路径(类似Ps里的路径)
                    //GraphicsPath gpath = new GraphicsPath();
                    ////gpath.AddEllipse(0, 0, 100,100);
                    //gpath.AddEllipse(Square / 2 - R / 2, Square / 2 - R / 2, R - 1, R - 1);
                    //g.SetClip(gpath);

                    //g.DrawImage(img, -(img.Width / 2 - Square / 2), -(img.Height / 2 - Square / 2));
                    ////保存截好的图
                    //bm.Save(path, ImageFormat.Jpeg);
                    Rectangle cutRec = new Rectangle()
                    {
                        X = img.Width / 2 - Square / 2,
                        Y = img.Height / 2 - Square / 2,
                        Width = Square,
                        Height = Square
                    };
                    var afterPic = cutPicture(img, cutRec);

                    for (int i = 0; i < afterPic.Height; i++)
                    {
                        for (int j = 0; j < afterPic.Width; j++)
                        {
                            if (inR(j, i, afterPic.Width / 2, afterPic.Height / 2, R / 2))
                            {
                               
                            }
                            else
                            {
                                afterPic.SetPixel(j,i,Color.White);
                            }
                        }
                    }

                    afterPic.Save(path, ImageFormat.Jpeg);
                }
               
            }
            catch (Exception ex)
            {
                throw new Exception($"{R}{Square}{path}"+" //// +"+  ex.ToString());
            }
           
        }
        private bool inR(int x, int y, int cenX, int cenY, int R)
        {
            double r = Math.Sqrt((x - cenX) * (x - cenX) + (y - cenY) * (y - cenY));
            return r <= R;
        }
        /// <summary>
        /// 多张图片的合并
        /// </summary>
        /// <param name="DirectoryName">目标文件夹</param>
        /// <param name="NumRows">行数</param>
        /// <param name="NumColumns">列数</param>
        /// <returns></returns>
        [SupportedOSPlatform("windows")]
        public BitmapImage CombinImage(string DirectoryName,int NumRows, int NumColumns,string plateStyle)
        {
            var mf = mICPlateMes.microplateAntibioticConcentrationMes.Find(p => p.name == plateStyle);
            if (mf == null)
            {
                throw new Exception("配置文件错误");
            }
            var map = configurationFileManagement.GetMapCfgByName(mf.Map);
            int dY = map.dx;
            int dX = map.dy;
            int width =  map.width;
            int height = map.height;

            // 初始化画布(最终的拼图画布)并设置宽高
            Bitmap bitMap = new Bitmap(dX * NumColumns, dY * NumRows);
            // 初始化画板
            Graphics g1 = Graphics.FromImage(bitMap);
            // 将画布涂为hei色(底部颜色可自行设置)
            g1.FillRectangle(System.Drawing.Brushes.White, new Rectangle(0, 0, dX * NumColumns, dY * NumRows));
            for (int i = 0; i < NumRows * NumColumns; i++)
            {
                try
                {
                    int centX = (dX - width) / 2 + (i % 12) * dX;
                    int centY = (dY - height) / 2 + (i / 12) * dY;
                    Image img0 = Image.FromFile(Path.Combine(DirectoryName, $"{i + 1}.jpg"));
                    Bitmap map0 = new Bitmap(img0);
                    g1.DrawImage(map0, centX, centY, width, height);
                    img0.Dispose();
                }
                catch
                {
                    //TODO 打开孔位 图片失败
                }
            }
            return BitmapToBitmapImage(bitMap);
        }


        [SupportedOSPlatform("windows")]
        public void CombinImageAndSave(string DirectoryName, string filename,int NumRows, int NumColumns, string plateStyle)
        {
            var mf = mICPlateMes.microplateAntibioticConcentrationMes.Find(p => p.name == plateStyle);
            if (mf == null)
            {
                throw new Exception("配置文件错误");
            }
            var map = configurationFileManagement.GetMapCfgByName(mf.Map);
          
            if (!Directory.Exists(DirectoryName))
            {
                DirectoryInfo dirInfo = new DirectoryInfo(DirectoryName);
                dirInfo.Create();
            }
            int dY = map.dx;
            int dX = map.dy;
            int width = map.width;
            int height = map.height;

            // 初始化画布(最终的拼图画布)并设置宽高
            Bitmap bitMap = new Bitmap(dX * NumColumns, dY * NumRows);
            // 初始化画板
            Graphics g1 = Graphics.FromImage(bitMap);
            // 将画布涂为hei色(底部颜色可自行设置)
            g1.FillRectangle(System.Drawing.Brushes.White, new Rectangle(0, 0, dX * NumColumns, dY * NumRows));
            for (int i = 0; i < NumRows * NumColumns; i++)
            {
                try
                {
                    int centX = (dX - width) / 2 + (i % 12) * dX;
                    int centY = (dY - height) / 2 + (i / 12) * dY;
                    Image img0 = Image.FromFile(Path.Combine("Image", filename, $"temp{i + 1}.jpeg"));
                    Bitmap map0 = new Bitmap(img0);
                    g1.DrawImage(map0, centX, centY, width, height);
                    img0.Dispose();
                }
                catch
                {
                    //TODO 打开孔位 图片失败
                }
            }
            bitMap.Save(Path.Combine(DirectoryName, $"{filename}.jpg"),ImageFormat.Jpeg);
        }

        public void DelPics(string DirectoryName)
        {

            DirectoryInfo directoryInfo = new DirectoryInfo(DirectoryName);
            var files = directoryInfo.GetFiles("temp??.jpeg");
            foreach ( var file in files )
            {
                try
                {
                    file.Delete();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
               
            }
        }

        [SupportedOSPlatform("windows")]
        public BitmapImage[] ShowAllImage(string DirectoryName)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(DirectoryName);
            int totalPics = directoryInfo.GetFiles("*.jpg").Length;
            BitmapImage[] ret = new BitmapImage[totalPics];

            for (int i = 0; i < totalPics; i++)
            {
                try
                {
                    string filePath = Path.Combine(DirectoryName, $"{i + 1}.jpg");
                    if (!File.Exists(filePath))
                        return null;
                    Image img0 = Image.FromFile(filePath);
                    Bitmap map0 = new Bitmap(img0);
                    ret[i]= BitmapToBitmapImage(map0);
                    img0.Dispose();
                }
                catch(Exception ex)
                {
                    return null;
                }
            }
            return ret;
        }


        //[SupportedOSPlatform("windows")]
        //private BitmapSource GetBitmapSourceFromBitmap(Bitmap bmp)
        //{

        //    int bW = bmp.Width, bH = bmp.Height;
        //    WriteableBitmap writableBmp = new WriteableBitmap(bW, bH, 96, 96, PixelFormats.BlackWhite, null);

        //    int rPixelBytes = bW * bH; //字节数
        //    BitmapData data = bmp.LockBits(new Rectangle(0, 0, bW, bH), ImageLockMode.ReadOnly,
        //        System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
        //    writableBmp.Lock();
        //    unsafe
        //    {
        //        Buffer.MemoryCopy(data.Scan0.ToPointer(), writableBmp.BackBuffer.ToPointer(), rPixelBytes, rPixelBytes);
        //    }
        //    writableBmp.AddDirtyRect(new Int32Rect(0, 0, bW, bH));
        //    writableBmp.Unlock();
        //    bmp.UnlockBits(data);
        //    return writableBmp;

        //}

        private BitmapImage BitmapToBitmapImage(Bitmap bitmap)
        {
            BitmapImage bitmapImage = new BitmapImage();
            using (System.IO.MemoryStream ms = new MemoryStream())
            {
                bitmap.Save(ms,ImageFormat.Bmp);
                bitmapImage.BeginInit();
                bitmapImage.StreamSource = ms;
                bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                
                bitmapImage.EndInit();
                bitmapImage.Freeze();
            }
            return bitmapImage;
        }

        public List<WellPlateItem> GetWellPlateItems(string DirectoryName,IHisRepository hisRepository)
        {
            List<WellPlateItem> items = new List<WellPlateItem>();
            if (!Directory.Exists(DirectoryName))
            {
                return items;
            }
            DirectoryInfo parentDirectoryInfo = new DirectoryInfo(DirectoryName);

            GetItems(parentDirectoryInfo.GetDirectories(), hisRepository);
            
            
            var temps=parentDirectoryInfo.GetDirectories().OrderByDescending(o => o.CreationTime)
                                      .GroupBy(o => o.CreationTime.ToString("yyyy-MM-dd"), name => new { wellPlateID = name }).ToList();

            foreach (var subDirectory in temps)
            {
                WellPlateItem item = new WellPlateItem();
                foreach (var value in subDirectory.ToList())
                {
                    string plateId = null;
                    string name = value.wellPlateID.Name;
                    int index = name.IndexOf("&");
                    if (value.wellPlateID.Name.Contains("h"))
                    {
                        int endIndex = name.LastIndexOf("-");
                        plateId = name.Substring(index + 1, endIndex - index - 1);
                    }
                    else
                        plateId = name.Substring(index + 1);
                    string sampleId = name.Substring(0, index);
                    var hisories = hisRepository.QueryHisByPlateName(plateId, sampleId);
                    if (hisories == null || hisories.Count == 0)
                        continue;
                    var hisoriy = hisories.FirstOrDefault();
                    if(items.Any(o=>o.DataTime==hisoriy.LoadTime.ToString("yyyy-MM-dd")))
                    {
                        var temp=items.FirstOrDefault(o => o.DataTime == hisoriy.LoadTime.ToString("yyyy-MM-dd"));
                        temp.WellPlateIDs.Add(value.wellPlateID.Name);
                    }
                    else
                    {
                        item = new WellPlateItem();
                        item.DataTime = hisoriy.LoadTime.ToString("yyyy-MM-dd");
                        item.WellPlateIDs.Add(value.wellPlateID.Name);
                        items.Add(item);
                    }
                }
            }
            items=items.OrderByDescending(o => o.DataTime).ToList();
            return items;
        }

        public List<WellPlateItem> GetWellPlateItemsByTime(string DirectoryName, DateTime? start, DateTime? end, IHisRepository hisRepository)
        {
            List<WellPlateItem> items = new List<WellPlateItem>();
            if (!Directory.Exists(DirectoryName))
            {
                return items;
            }
            DirectoryInfo parentDirectoryInfo = new DirectoryInfo(DirectoryName);
            var directories = parentDirectoryInfo.GetDirectories()/*.AsEnumerable()*/;
            //if (start != null && end != null)
            //{
            //    directories = directories.Where(o => o.CreationTime >= start && o.CreationTime <= end).ToArray();
            //}
            //else if (end != null)
            //{
            //    directories = directories.Where(o => o.CreationTime <= end).ToArray();
            //}
            //else if (start != null)
            //{
            //    directories = directories.Where(o => o.CreationTime >= start).ToArray();
            //}
            items=GetItems(directories, hisRepository);
            if (start != null && end != null)
            {
                if(start==end)
                {
                    end= start?.AddDays(1);
                }
                items = items.Where(o => DateTime.Parse(o.DataTime) >= start && DateTime.Parse(o.DataTime) <= end).ToList();
            }
            else if (end != null)
            {
                items = items.Where(o => DateTime.Parse(o.DataTime) <= end).ToList();
            }
            else if (start != null)
            {
                items = items.Where(o => DateTime.Parse(o.DataTime) >= start).ToList();
            }

            //var subDirectories= directories.OrderByDescending(o => o.CreationTime)
            //                     .GroupBy(o => o.CreationTime.ToString("yyyy-MM-dd"), name => new { wellPlateID = name }).ToList();
            //foreach (var subDirectory in subDirectories)
            //{
            //    WellPlateItem item = new WellPlateItem() { DataTime = subDirectory.Key };
            //    foreach (var value in subDirectory.ToList())
            //    {
            //        item.WellPlateIDs.Add(value.wellPlateID.Name);
            //    }
            //    items.Add(item);
            //}

            return items;
        }

        private List<WellPlateItem> GetItems(DirectoryInfo[] directoryInfos,IHisRepository hisRepository)
        {
            List<WellPlateItem> items = new List<WellPlateItem>();
            var temps = directoryInfos.OrderByDescending(o => o.CreationTime)
                                      .GroupBy(o => o.CreationTime.ToString("yyyy-MM-dd"), name => new { wellPlateID = name }).ToList();

            foreach (var subDirectory in temps)
            {
                WellPlateItem item = new WellPlateItem();
                foreach (var value in subDirectory.ToList())
                {
                    string plateId = null;
                    string name = value.wellPlateID.Name;
                    int index = name.IndexOf("&");
                    if (value.wellPlateID.Name.Contains("h"))
                    {
                        int endIndex = name.LastIndexOf("-");
                        plateId = name.Substring(index + 1, endIndex - index - 1);
                    }
                    else
                        plateId = name.Substring(index + 1);
                    string sampleId = name.Substring(0, index);
                    var hisories = hisRepository.QueryHisByPlateName(plateId, sampleId);
                    if (hisories == null || hisories.Count == 0)
                        continue;
                    var hisoriy = hisories.FirstOrDefault();
                    if (items.Any(o => o.DataTime == hisoriy.LoadTime.ToString("yyyy-MM-dd")))
                    {
                        var temp = items.FirstOrDefault(o => o.DataTime == hisoriy.LoadTime.ToString("yyyy-MM-dd"));
                        temp.WellPlateIDs.Add(value.wellPlateID.Name);
                    }
                    else
                    {
                        item = new WellPlateItem();
                        item.DataTime = hisoriy.LoadTime.ToString("yyyy-MM-dd");
                        item.WellPlateIDs.Add(value.wellPlateID.Name);
                        items.Add(item);
                    }
                }
            }
            items = items.OrderByDescending(o => o.DataTime).ToList();
            return items;
        }

        public string[] GetFileNames(string DirectoryName)
        {
            if (Directory.Exists(DirectoryName))
            {
                DirectoryInfo parentDirectoryInfo = new DirectoryInfo(DirectoryName);
                DirectoryInfo[] subDirectories = parentDirectoryInfo.GetDirectories().OrderBy(o => o.CreationTime).ToArray();
                string[] names = new string[subDirectories.Length];
                for (int i = 0; i < subDirectories.Length; i++)
                {
                    names[i] = subDirectories[i].Name;
                }
                return names;
            }
            else { return null; }
        }

        public string[] GetFileNamesByTime(string DirectoryName,DateTime? start,DateTime? end)
        {
            if (!Directory.Exists(DirectoryName))
            {
                return null;
            }

            DirectoryInfo parentDirectoryInfo = new DirectoryInfo(DirectoryName);
            DirectoryInfo[] subDirectories= parentDirectoryInfo.GetDirectories().OrderBy(o => o.CreationTime).ToArray(); ;
            if (start!=null&& end != null)
            {
                subDirectories = parentDirectoryInfo.GetDirectories()
                                 .Where(o => o.CreationTime >= start && o.CreationTime <= end)
                                 .OrderBy(o => o.CreationTime).ToArray();
            }
            else if (end!=null)
            {
                subDirectories= parentDirectoryInfo.GetDirectories()
                                .Where(o=>o.CreationTime <= end)
                                .OrderBy(o => o.CreationTime).ToArray();
            }
            else if(start!=null)
            {
                subDirectories = parentDirectoryInfo.GetDirectories()
                                .Where(o => o.CreationTime >= start)
                                .OrderBy(o => o.CreationTime).ToArray();
            }
            string[] names = new string[subDirectories.Length];
            for (int i = 0; i < subDirectories.Length; i++)
            {
                names[i] = subDirectories[i].Name;
            }
            return names;
        }

        [SupportedOSPlatform("windows")]
        public BitmapImage ShowSingleImage(string DirectoryName, int index)
        {
            Image img0 = Image.FromFile(Path.Combine(DirectoryName, $"{index + 1}.jpg"));
            Bitmap map0 = new Bitmap(img0);
            return BitmapToBitmapImage(map0);
        }
    }
}
